// *************************************************************************************************
//
// MK3D Engine
// --------------------------------------
// Copyright (C) 2007-2011 Zeb (mailto: zebbey@gmail.com)
//
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// *************************************************************************************************

#include "mk_header.h"
#include "mk_painter.h"
#include "mk_render_device.h"
#include "mk_error.h"
#include "mk_engine.h"
#include "mk_d3d9_render_device.h"
#include "mk_resource_manager.h"
#include "mk_camera.h"

namespace MK3DE
{
	static const int __PRIM_TYPE_LINE2D = 0;
	static const int __PRIM_TYPE_LINE3D = 1;
	static const int __PRIM_TYPE_QUAD2D = 2;
	static const int __PRIM_TYPE_TRIANGLE3D = 3;

	static const char* __TECH_PAINT_2D = "paint2D";
	static const char* __TECH_PAINT_3D = "paint3D";

	static const BYTE __EFFECT[] = "\
		float4x4 MAT_WORLD_VIEW_PROJ;\
		void Vert3D(float4 iPos : POSITION,\
			float4 iColor : COLOR,\
			float2 iTex : TEXCOORD,\
			out float4 oPos : POSITION,\
			out float4 oColor : COLOR,\
			out float2 oTex : TEXCOORD)\
		{\
			oPos = mul(iPos, MAT_WORLD_VIEW_PROJ);\
			oColor = iColor;\
			oTex = iTex;\
		}\
		technique paint2D\
		{\
			pass P0\
			{\
				CullMode		= None;\
				Lighting		= False;\
				ZEnable			= False;\
				ZWriteEnable = False;\
				AlphaBlendEnable = True;\
				SrcBlend = SrcAlpha;\
				DestBlend = InvSrcAlpha;\
				AlphaTestEnable = False;\
				ColorOp[0] = Modulate;\
				AlphaOp[0] = Modulate;\
				ColorArg1[0] = Texture;\
				ColorArg2[0] = Diffuse;\
				AlphaArg1[0] = Texture;\
				AlphaArg2[0] = Diffuse;\
				ColorOp[1] = Disable;\
				AlphaOp[1] = Disable;\
			}\
		}\
		technique paint3D\
		{\
			pass P0\
			{\
				CullMode		= None;\
				Lighting		= False;\
				ZEnable			= True;\
				ZWriteEnable = True;\
				AlphaBlendEnable = True;\
				SrcBlend = SrcAlpha;\
				DestBlend = InvSrcAlpha;\
				AlphaTestEnable = False;\
				VertexShader = compile vs_2_0 Vert3D();\
			}\
		}\
	";

	CPainter::CPainter() :
	_bufferLine2D(NULL),
		_bufferLine3D(NULL),
		_bufferQuad2D(NULL),
		_bufferTriangle3D(NULL),
		_vbLine2D(NULL),
		_vbLine3D(NULL),
		_vbQuad2D(NULL),
		_vbTriangle3D(NULL),
		_riLine2D(NULL),
		_riLine3D(NULL),
		_riQuad2D(NULL),
		_riTriangle3D(NULL),
		_currentTexture(NULL),
		_currentPrimitiveType(__PRIM_TYPE_LINE2D),
		_shader(NULL)
	{

	}

	CPainter::~CPainter()
	{
		CRenderDevice* rd = GetEngine()->GetRenderDevice();

		SAFE_RELEASE(_shader);

		SAFE_RELEASE(_vbLine2D);
		SAFE_RELEASE(_vbLine3D);
		SAFE_RELEASE(_vbQuad2D);
		SAFE_RELEASE(_vbTriangle3D);

		rd->DestroyRenderInput(_riLine2D);
		rd->DestroyRenderInput(_riLine3D);
		rd->DestroyRenderInput(_riQuad2D);
		rd->DestroyRenderInput(_riTriangle3D);

		SAFE_DELETE_ARRAY(_bufferLine2D);
		SAFE_DELETE_ARRAY(_bufferLine3D);
		SAFE_DELETE_ARRAY(_bufferQuad2D);
		SAFE_DELETE_ARRAY(_bufferTriangle3D);
	}

	BOOL CPainter::Init(DWORD bufferSize)
	{
		BOOL ret = FALSE;

		CRenderDevice* rd = GetEngine()->GetRenderDevice();
		CResourceManager* rm = GetEngine()->GetResourceManager();

		ret = rm->GetShaderFromMemory(__EFFECT, sizeof(__EFFECT), _shader);
		MK_PROCESS_ERROR(ret);

		ret = rm->GetVertexBuffer(sizeof(VERT_2D_COL_TEX1), bufferSize * 2, (HARDWARE_BUFFER_USAGE)(HBU_DYNAMIC|HBU_WRITE_ONLY), _vbLine2D);
		MK_PROCESS_ERROR(ret);

		ret = rm->GetVertexBuffer(sizeof(VERT_3D_COL_TEX1), bufferSize * 2, (HARDWARE_BUFFER_USAGE)(HBU_DYNAMIC|HBU_WRITE_ONLY), _vbLine3D);
		MK_PROCESS_ERROR(ret);

		ret = rm->GetVertexBuffer(sizeof(VERT_2D_COL_TEX1), bufferSize * 6, (HARDWARE_BUFFER_USAGE)(HBU_DYNAMIC|HBU_WRITE_ONLY), _vbQuad2D);
		MK_PROCESS_ERROR(ret);

		ret = rm->GetVertexBuffer(sizeof(VERT_3D_COL_TEX1), bufferSize * 3, (HARDWARE_BUFFER_USAGE)(HBU_DYNAMIC|HBU_WRITE_ONLY), _vbTriangle3D);
		MK_PROCESS_ERROR(ret);

		RenderInputElemDesc rieLine2D[] = { 
			RenderInputElemDesc(SU_POSITION_T, 0, 0, 0),
			RenderInputElemDesc(SU_COLOR, 0, 16, 0),
			RenderInputElemDesc(SU_TEXCOORD, 0, 20, 0)
		};

		RenderInputElemDesc rieLine3D[] = { 
			RenderInputElemDesc(SU_POSITION, 0, 0, 0),
			RenderInputElemDesc(SU_COLOR, 0, 12, 0),
			RenderInputElemDesc(SU_TEXCOORD, 0, 16, 0)
		};

		RenderInputElemDesc rieQuad2D[] = { 
			RenderInputElemDesc(SU_POSITION_T, 0, 0, 0),
			RenderInputElemDesc(SU_COLOR, 0, 16, 0),
			RenderInputElemDesc(SU_TEXCOORD, 0, 20, 0)
		};

		RenderInputElemDesc rieTriangle3D[] = {
			RenderInputElemDesc(SU_POSITION, 0, 0, 0),
			RenderInputElemDesc(SU_COLOR, 0, 12, 0),
			RenderInputElemDesc(SU_TEXCOORD, 0, 16, 0)
		};

		ret = rd->CreateRenderInput(rieLine2D, 3, _riLine2D);
		MK_PROCESS_ERROR(ret);

		ret = rd->CreateRenderInput(rieLine3D, 3, _riLine3D);
		MK_PROCESS_ERROR(ret);

		ret = rd->CreateRenderInput(rieQuad2D, 3, _riQuad2D);
		MK_PROCESS_ERROR(ret);

		ret = rd->CreateRenderInput(rieTriangle3D, 3, _riTriangle3D);

		ret = _riLine2D->SetVertexBuffer(0, _vbLine2D);
		MK_PROCESS_ERROR(ret);

		ret = _riLine3D->SetVertexBuffer(0, _vbLine3D);
		MK_PROCESS_ERROR(ret);

		ret = _riQuad2D->SetVertexBuffer(0, _vbQuad2D);
		MK_PROCESS_ERROR(ret);

		ret = _riTriangle3D->SetVertexBuffer(0, _vbTriangle3D);
		MK_PROCESS_ERROR(ret);

		_size = bufferSize;
		_bufferLine2D = new LINE_2D[bufferSize];
		MK_PROCESS_ERROR(_bufferLine2D);

		_bufferLine3D = new LINE_3D[bufferSize];
		MK_PROCESS_ERROR(_bufferLine3D);

		_bufferQuad2D = new QUAD_2D[bufferSize];
		MK_PROCESS_ERROR(_bufferQuad2D);

		_bufferTriangle3D = new TRIANGLE_3D[bufferSize];
		MK_PROCESS_ERROR(_bufferTriangle3D);

		_count = 0;

		ret = TRUE;
Exit0:
		return ret;
	}

	BOOL CPainter::DrawLine2D(D3DXVECTOR2& pos1, D3DXVECTOR2& pos2, DWORD color1, DWORD color2)
	{
		if (_currentPrimitiveType != __PRIM_TYPE_LINE2D || _currentTexture)
		{
			if (!Flush())
				return FALSE;
		}

		_currentPrimitiveType = __PRIM_TYPE_LINE2D;
		_currentTexture = NULL;

		LINE_2D& line = _bufferLine2D[_count++];

		line.v[0].pos = D3DXVECTOR4(pos1.x, pos1.y, 0, 1.0f);
		line.v[1].pos = D3DXVECTOR4(pos2.x, pos2.y, 0, 1.0f);

		line.v[0].color = color1;
		line.v[1].color = color2;

		line.v[0].uv = D3DXVECTOR2(0, 0);
		line.v[1].uv = D3DXVECTOR2(0, 0);

		if (_count == _size)
			return __FlushLine2D();

		return TRUE;
	}

	BOOL CPainter::DrawRect(Rect2D& rect, RectColor& color)
	{
		BOOL ret = FALSE;
		D3DXVECTOR2 v1(rect.leftTop.x, rect.leftTop.y);
		D3DXVECTOR2 v2(rect.rightBottom.x, rect.leftTop.y);
		D3DXVECTOR2 v3(rect.rightBottom.x, rect.rightBottom.y);
		D3DXVECTOR2 v4(rect.leftTop.x, rect.rightBottom.y);
		ret = DrawLine2D(v1, v2, color.leftTop, color.rightTop);
		MK_PROCESS_ERROR(ret);

		ret = DrawLine2D(v2, v3, color.rightTop, color.rightBottom);
		MK_PROCESS_ERROR(ret);

		ret = DrawLine2D(v3, v4, color.rightBottom, color.leftBottom);
		MK_PROCESS_ERROR(ret);

		ret = DrawLine2D(v4, v1, color.leftBottom, color.leftTop);
		MK_PROCESS_ERROR(ret);

		ret = TRUE;
Exit0:
		return ret;
	}

	BOOL CPainter::DrawImage2D(Rect2D& rect, RectColor& color, CTexture2D* pTexture)
	{
		if (_currentPrimitiveType != __PRIM_TYPE_QUAD2D || _currentTexture != pTexture)
		{
			if (!Flush())
				return FALSE;
		}

		_currentPrimitiveType = __PRIM_TYPE_QUAD2D;
		_currentTexture = pTexture;

		QUAD_2D& quad = _bufferQuad2D[_count++];

		quad.v[0].pos = D3DXVECTOR4(rect.leftTop.x, rect.leftTop.y, 0, 1.0f);
		quad.v[1].pos = D3DXVECTOR4(rect.rightBottom.x, rect.leftTop.y, 0, 1.0f);
		quad.v[2].pos = D3DXVECTOR4(rect.leftTop.x, rect.rightBottom.y, 0, 1.0f);
		quad.v[3].pos = D3DXVECTOR4(rect.leftTop.x, rect.rightBottom.y, 0, 1.0f);
		quad.v[4].pos = D3DXVECTOR4(rect.rightBottom.x, rect.leftTop.y, 0, 1.0f);
		quad.v[5].pos = D3DXVECTOR4(rect.rightBottom.x, rect.rightBottom.y, 0, 1.0f);

		quad.v[0].color = color.leftTop;
		quad.v[1].color = color.rightTop;
		quad.v[2].color = color.leftBottom;
		quad.v[3].color = color.leftBottom;
		quad.v[4].color = color.rightTop;
		quad.v[5].color = color.rightBottom;

		quad.v[0].uv = D3DXVECTOR2(0, 0);
		quad.v[1].uv = D3DXVECTOR2(1, 0);
		quad.v[2].uv = D3DXVECTOR2(0, 1);
		quad.v[3].uv = D3DXVECTOR2(0, 1);
		quad.v[4].uv = D3DXVECTOR2(1, 0);
		quad.v[5].uv = D3DXVECTOR2(1, 1);

		if (_count == _size)
			return __FlushQuad2D();

		return TRUE;

	}

	BOOL CPainter::DrawImageSub2D(Rect2D& rect, Rect2D& srcRect, RectColor& color, CTexture2D* pTexture)
	{
		if (_currentPrimitiveType != __PRIM_TYPE_QUAD2D || pTexture != _currentTexture)
		{
			if (!Flush())
				return FALSE;
		}

		_currentPrimitiveType = __PRIM_TYPE_QUAD2D;
		_currentTexture = pTexture;

		QUAD_2D& quad = _bufferQuad2D[_count++];

		quad.v[0].pos = D3DXVECTOR4(rect.leftTop.x - 0.5f, rect.leftTop.y - 0.5f, 0, 1.0f);
		quad.v[1].pos = D3DXVECTOR4(rect.rightBottom.x - 0.5f, rect.leftTop.y - 0.5f, 0, 1.0f);
		quad.v[2].pos = D3DXVECTOR4(rect.leftTop.x - 0.5f, rect.rightBottom.y - 0.5f, 0, 1.0f);
		quad.v[3].pos = D3DXVECTOR4(rect.leftTop.x - 0.5f, rect.rightBottom.y - 0.5f, 0, 1.0f);
		quad.v[4].pos = D3DXVECTOR4(rect.rightBottom.x - 0.5f, rect.leftTop.y - 0.5f, 0, 1.0f);
		quad.v[5].pos = D3DXVECTOR4(rect.rightBottom.x - 0.5f, rect.rightBottom.y - 0.5f, 0, 1.0f);

		quad.v[0].color = color.leftTop;
		quad.v[1].color = color.rightTop;
		quad.v[2].color = color.leftBottom;
		quad.v[3].color = color.leftBottom;
		quad.v[4].color = color.rightTop;
		quad.v[5].color = color.rightBottom;

		if (pTexture)
		{
			float width = (float)pTexture->GetWidth();
			float height = (float)pTexture->GetHeight();

			float leftTopX = srcRect.leftTop.x / width;
			float leftTopY = srcRect.leftTop.y / height;

			float rightBottomX = srcRect.rightBottom.x / width;
			float rightBottomY = srcRect.rightBottom.y / height;

			quad.v[0].uv = D3DXVECTOR2(leftTopX, leftTopY);
			quad.v[1].uv = D3DXVECTOR2(rightBottomX, leftTopY);
			quad.v[2].uv = D3DXVECTOR2(leftTopX, rightBottomY);
			quad.v[3].uv = D3DXVECTOR2(leftTopX, rightBottomY);
			quad.v[4].uv = D3DXVECTOR2(rightBottomX, leftTopY);
			quad.v[5].uv = D3DXVECTOR2(rightBottomX, rightBottomY);
		}


		if (_count == _size)
			return __FlushQuad2D();

		return TRUE;
	}

	BOOL CPainter::DrawLine3D(D3DXVECTOR3& pos1, D3DXVECTOR3& pos2, DWORD color1, DWORD color2)
	{
		if (_currentPrimitiveType != __PRIM_TYPE_LINE3D || _currentTexture)
		{
			if (!Flush())
				return FALSE;
		}

		_currentPrimitiveType = __PRIM_TYPE_LINE3D;
		_currentTexture = NULL;

		LINE_3D& line = _bufferLine3D[_count++];

		line.v[0].pos = D3DXVECTOR3(pos1.x, pos1.y, pos1.z);
		line.v[1].pos = D3DXVECTOR3(pos2.x, pos2.y, pos2.z);

		line.v[0].color = color1;
		line.v[1].color = color2;

		line.v[0].uv = D3DXVECTOR2(0, 0);
		line.v[1].uv = D3DXVECTOR2(0, 0);

		if (_count == _size)
			return __FlushLine3D();

		return TRUE;
	}

	BOOL CPainter::DrawTriangle(D3DXVECTOR3& pos1, D3DXVECTOR3& pos2, D3DXVECTOR3& pos3, D3DXVECTOR2& uv1, D3DXVECTOR2& uv2, D3DXVECTOR2& uv3, DWORD color1, DWORD color2, DWORD color3, CTexture2D* pTexture)
	{
		if (_currentPrimitiveType != __PRIM_TYPE_TRIANGLE3D || pTexture != _currentTexture)
		{
			if (!Flush())
				return FALSE;
		}

		_currentPrimitiveType = __PRIM_TYPE_TRIANGLE3D;
		_currentTexture = pTexture;

		TRIANGLE_3D& triangle = _bufferTriangle3D[_count++];

		triangle.v[0].pos = pos1;
		triangle.v[1].pos = pos2;
		triangle.v[2].pos = pos3;

		triangle.v[0].color = color1;
		triangle.v[1].color = color2;
		triangle.v[2].color = color3;

		triangle.v[0].uv = uv1;
		triangle.v[1].uv = uv2;
		triangle.v[2].uv = uv3;

		if (_count == _size)
			return __FlushTriangle3D();

		return TRUE;
	}

	BOOL CPainter::DrawAABB(AABB& aabb, DWORD color)
	{
		DrawLine3D(aabb.minPt, D3DXVECTOR3(aabb.maxPt.x, aabb.minPt.y, aabb.minPt.z), color, color);
		DrawLine3D(aabb.minPt, D3DXVECTOR3(aabb.minPt.x, aabb.maxPt.y, aabb.minPt.z), color, color);
		DrawLine3D(aabb.minPt, D3DXVECTOR3(aabb.minPt.x, aabb.minPt.y, aabb.maxPt.z), color, color);

		DrawLine3D(aabb.maxPt, D3DXVECTOR3(aabb.minPt.x, aabb.maxPt.y, aabb.maxPt.z), color, color);
		DrawLine3D(aabb.maxPt, D3DXVECTOR3(aabb.maxPt.x, aabb.minPt.y, aabb.maxPt.z), color, color);
		DrawLine3D(aabb.maxPt, D3DXVECTOR3(aabb.maxPt.x, aabb.maxPt.y, aabb.minPt.z), color, color);

		DrawLine3D(D3DXVECTOR3(aabb.minPt.x, aabb.maxPt.y, aabb.minPt.z), D3DXVECTOR3(aabb.minPt.x, aabb.maxPt.y, aabb.maxPt.z), color, color);
		DrawLine3D(D3DXVECTOR3(aabb.minPt.x, aabb.maxPt.y, aabb.minPt.z), D3DXVECTOR3(aabb.maxPt.x, aabb.maxPt.y, aabb.minPt.z), color, color);
		DrawLine3D(D3DXVECTOR3(aabb.minPt.x, aabb.minPt.y, aabb.maxPt.z), D3DXVECTOR3(aabb.minPt.x, aabb.maxPt.y, aabb.maxPt.z), color, color);
		DrawLine3D(D3DXVECTOR3(aabb.maxPt.x, aabb.minPt.y, aabb.minPt.z), D3DXVECTOR3(aabb.maxPt.x, aabb.maxPt.y, aabb.minPt.z), color, color);

		DrawLine3D(D3DXVECTOR3(aabb.maxPt.x, aabb.minPt.y, aabb.maxPt.z), D3DXVECTOR3(aabb.maxPt.x, aabb.minPt.y, aabb.minPt.z), color, color);
		DrawLine3D(D3DXVECTOR3(aabb.maxPt.x, aabb.minPt.y, aabb.maxPt.z), D3DXVECTOR3(aabb.minPt.x, aabb.minPt.y, aabb.maxPt.z), color, color);

		return TRUE;
	}

	BOOL CPainter::Flush()
	{
		if (_currentPrimitiveType == __PRIM_TYPE_LINE2D)
			__FlushLine2D();
		else if (_currentPrimitiveType == __PRIM_TYPE_LINE3D)
			__FlushLine3D();
		else if (_currentPrimitiveType == __PRIM_TYPE_QUAD2D)
			__FlushQuad2D();
		else if (_currentPrimitiveType == __PRIM_TYPE_TRIANGLE3D)
			__FlushTriangle3D();
		return TRUE;
	}

	BOOL CPainter::__FlushLine2D()
	{
		if (_count == 0)
			return TRUE;

		BOOL ret = FALSE;

		CEngine* engine = GetEngine();
		CRenderDevice* rd = engine->GetRenderDevice();

		VERT_2D_COL_TEX1* p;
		_vbLine2D->Lock((void*&)p, 0, 0, LO_DISCARD);
		memcpy(p, _bufferLine2D, sizeof(VERT_2D_COL_TEX1) * 2 * _count);
		_vbLine2D->Unlock();

		ret = rd->BindRenderInput(_riLine2D);
		MK_PROCESS_ERROR(ret);

		ret = rd->SetTexture(0, NULL);
		MK_PROCESS_ERROR(ret);

		DWORD passNum;
		if (_shader->TechniqueBegin(__TECH_PAINT_2D, passNum))
		{
			for (DWORD pass = 0; pass < passNum; ++pass)
			{
				if (_shader->PassBegin(pass))
				{
					ret = rd->DrawPrimitive(PT_LINELIST, 0, 0, _count * 2, 0, _count);
					MK_PROCESS_ERROR(ret);

					_shader->PassEnd();
				}
			}

			_shader->TechniqueEnd();
		}

		_count = 0;
		ret = TRUE;
Exit0:
		return ret;
	}

	BOOL CPainter::__FlushTriangle3D()
	{
		if (_count == 0)
			return TRUE;

		BOOL ret = FALSE;

		CEngine* engine = GetEngine();
		CRenderDevice* rd = engine->GetRenderDevice();

		VERT_3D_COL_TEX1* p;
		_vbTriangle3D->Lock((void*&)p, 0, 0, LO_DISCARD);
		memcpy(p, _bufferTriangle3D, sizeof(VERT_3D_COL_TEX1) * 3 * _count);
		_vbTriangle3D->Unlock();

		D3DXMATRIX mvp = engine->GetCurrentCamera()->GetViewProjMatrix();
		_shader->SetFloatArray(SCN_MAT_WORLD_VIEW_PROJ, (float*)&mvp, 16);

		ret = rd->BindRenderInput(_riTriangle3D);
		MK_PROCESS_ERROR(ret);

		ret = rd->SetTexture(0, _currentTexture);
		MK_PROCESS_ERROR(ret);

		DWORD passNum;
		if (_shader->TechniqueBegin(__TECH_PAINT_3D, passNum))
		{
			for (DWORD pass = 0; pass < passNum; ++pass)
			{
				if (_shader->PassBegin(pass))
				{
					ret = rd->DrawPrimitive(PT_TRIANGLELIST, 0, 0, _count * 3, 0, _count);
					MK_PROCESS_ERROR(ret);

					_shader->PassEnd();
				}
			}

			_shader->TechniqueEnd();
		}

		_count = 0;
		ret = TRUE;
Exit0:
		return ret;
	}

	BOOL CPainter::__FlushLine3D()
	{
		if (_count == 0)
			return TRUE;

		BOOL ret = FALSE;

		CEngine* engine = GetEngine();
		CRenderDevice* rd = engine->GetRenderDevice();

		VERT_3D_COL_TEX1* p;
		_vbLine3D->Lock((void*&)p, 0, 0, LO_DISCARD);
		memcpy(p, _bufferLine3D, sizeof(VERT_3D_COL_TEX1) * 2 * _count);
		_vbLine3D->Unlock();

		D3DXMATRIX mvp = engine->GetCurrentCamera()->GetViewProjMatrix();
		_shader->SetFloatArray(SCN_MAT_WORLD_VIEW_PROJ, (float*)&mvp, 16);

		ret = rd->BindRenderInput(_riLine3D);
		MK_PROCESS_ERROR(ret);

		ret = rd->SetTexture(0, _currentTexture);
		MK_PROCESS_ERROR(ret);

		DWORD passNum;
		if (_shader->TechniqueBegin(__TECH_PAINT_3D, passNum))
		{
			for (DWORD pass = 0; pass < passNum; ++pass)
			{
				if (_shader->PassBegin(pass))
				{
					ret = rd->DrawPrimitive(PT_LINELIST, 0, 0, _count * 2, 0, _count);
					MK_PROCESS_ERROR(ret);

					_shader->PassEnd();
				}
			}

			_shader->TechniqueEnd();
		}

		_count = 0;
		ret = TRUE;
Exit0:
		return ret;
	}

	BOOL CPainter::__FlushQuad2D()
	{
		if (_count == 0)
			return TRUE;

		BOOL ret = FALSE;

		CEngine* engine = GetEngine();
		CRenderDevice* rd = engine->GetRenderDevice();

		VERT_2D_COL_TEX1* p;
		_vbQuad2D->Lock((void*&)p, 0, 0, LO_DISCARD);
		memcpy(p, _bufferQuad2D, sizeof(VERT_2D_COL_TEX1) * 6 * _count);
		_vbQuad2D->Unlock();

		ret = rd->BindRenderInput(_riQuad2D);
		MK_PROCESS_ERROR(ret);

		ret = rd->SetTexture(0, _currentTexture);
		MK_PROCESS_ERROR(ret);

		DWORD passNum;
		if (_shader->TechniqueBegin(__TECH_PAINT_2D, passNum))
		{
			for (DWORD pass = 0; pass < passNum; ++pass)
			{
				if (_shader->PassBegin(pass))
				{
					ret = rd->DrawPrimitive(PT_TRIANGLELIST, 0, 0, _count * 6, 0, _count * 2);
					MK_PROCESS_ERROR(ret);

					_shader->PassEnd();
				}
			}

			_shader->TechniqueEnd();
		}

		_count = 0;
		ret = TRUE;
Exit0:
		return ret;
	}
}